<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Canvas图片简单处理</title>
</head>

<body>
  <div>
    <button onclick="onReverse()">左右反转</button>
    <button onclick="onMosaic()">马赛克</button>
    <button onclick="onPartMosaic()">局部马赛克</button>
  </div>
  <canvas id="cvs" draggable="true"></canvas>
</body>
<script>
  const cvs = document.querySelector('#cvs')
  const ctx = cvs.getContext('2d')
  const img = new Image()
  img.src = 'https://cdn.pixabay.com/photo/2022/11/29/11/31/robin-7624340__480.jpg'
  img.setAttribute('crossOrigin', '')
  img.onload = () => {
    cvs.width = img.width / 2
    cvs.height = img.height / 2
    ctx.drawImage(img, 0, 0, cvs.width, cvs.height)
  }
  // 反转
  function onReverse() {
    const imgData = ctx.getImageData(0, 0, cvs.width, cvs.height)
    const data = imgData.data
    const w = cvs.width * 4
    for (let i = 0; i < data.length; i += 4) {
      const r = data[i]
      const g = data[i + 1]
      const b = data[i + 2]
      const a = data[i + 3]
      // 左右等比位置的像素交换
      if (i % w < w / 2) {
        const newI = i + (w - i % w * 2)

        data[i] = data[newI]
        data[i + 1] = data[newI + 1]
        data[i + 2] = data[newI + 2]
        data[i + 3] = data[newI + 3]

        data[newI] = r
        data[newI + 1] = g
        data[newI + 2] = b
        data[newI + 3] = a
      }

    }
    ctx.putImageData(imgData, 0, 0)
  }
  let isMosaic = false
  // 马赛克
  function onMosaic() {
    // 马赛克比例
    const bl = 20
    if (isMosaic) {
      isMosaic = false
      return ctx.drawImage(img, 0, 0, cvs.width, cvs.height)
    }
    isMosaic = true
    const imgData = ctx.getImageData(0, 0, cvs.width, cvs.height)
    const data = imgData.data
    for (let i = 0; i < data.length; i += 4 * bl) {
      for (let b = 0; b < bl; b++) {
        data[i + b * 4] = data[i]
        data[i + 1 + b * 4] = data[i + 1]
        data[i + 2 + b * 4] = data[i + 2]
        data[i + 3 + b * 4] = data[i + 3]
      }
    }
    ctx.putImageData(imgData, 0, 0)
  }
  // 局部马赛克
  function onPartMosaic() {
    // 马赛克比例
    const bl = 10
    // 马赛克区域
    const parts = [
      {
        partX: 200,
        partY: 100,
        partWidth: 250,
        partHeight: 100
      },
      {
        partX: 270,
        partY: 242,
        partWidth: 90,
        partHeight: 50
      }
    ]
    if (isMosaic) {
      isMosaic = false
      return ctx.drawImage(img, 0, 0, cvs.width, cvs.height)
    }
    isMosaic = true
    const imgData = ctx.getImageData(0, 0, cvs.width, cvs.height)
    const data = imgData.data
    for (let i = 0; i < data.length; i += 4 * bl) {
      const x = (i / 4) % cvs.width
      const y = parseInt((i / 4) / cvs.width)
      // 有一个返回true，则result为true
      const result = parts.some(v => {
        return x >= v.partX && x <= v.partX + v.partWidth && y >= v.partY && y <= v.partY + v.partHeight
      })
      if (result) {
        for (let b = 0; b < bl; b++) {
          data[i + b * 4] = data[i]
          data[i + 1 + b * 4] = data[i + 1]
          data[i + 2 + b * 4] = data[i + 2]
          data[i + 3 + b * 4] = data[i + 3]
        }
      }
    }
    ctx.putImageData(imgData, 0, 0)
  }
</script>

</html>